﻿#include "ScriptSaveLoader.h"

#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <qfile.h>

#include "FileWriter.h"
#include "FileReader.h"
#include "ScriptRunner.h"
#include "ScriptInstructionFactory.h"
#include "LogSaver.h"

ScriptSaveLoader::ScriptSaveLoader(QObject* parent) :QObject(parent)
{}
ScriptSaveLoader::~ScriptSaveLoader()
{}

bool ScriptSaveLoader::saveAsScriptFile(QString filePath)//另存为脚本文件
{
  if (filePath.isEmpty()) {
      return false;
    }
  bool isOk = false;
  QVector<QVector<QVector<float>>> script = ScriptInstructionFactory::scriptListToFloatList(scriptRunner->getScript(),&isOk);
  if (!isOk)
    {
      logSaver->saveLog(QStringLiteral("%1：保存脚本%2过程中格式转换出错").arg(objectName()).arg(filePath), LogSaver::Critical);
      return false;
    }
  QJsonObject scriptObject;
  for (int i = 0; i < script.size(); ++i) {
      QJsonObject secondScriptObject;
      QVector<QVector<float>> codeBlock1 = script.at(i);//取出当前代码块
      for (int j = 0; j < codeBlock1.size(); ++j) {//装配当前代码块
          QJsonObject thirdScriptObject;
          QVector<float> instruction1 = codeBlock1.at(j);//取出当前指令
          for (int k = 0; k < instruction1.size(); ++k) {
              thirdScriptObject.insert(QString::number(k), QString::number(instruction1.at(k), 'f', accuracy));//将当前指令的第k个参数的值作为arg节点的值
            }
          secondScriptObject.insert(QString::number(j), thirdScriptObject);//添加指令到代码块
        }
      scriptObject.insert(QString::number(i), secondScriptObject);//添加代码块到脚本
    }
  //输出到文件
  QJsonDocument document;
  document.setObject(scriptObject);
  QByteArray scriptData = document.toJson();
  fileWriter->saveAsFile<ScriptSaveLoader>(filePath, scriptData, FileWriter::WriteToFile, this, &ScriptSaveLoader::slot_saveScriptFileSuccessfule, &ScriptSaveLoader::slot_saveScriptFileFailed);
  return true;
}

bool ScriptSaveLoader::loadScriptFile(QString filepath)//载入脚本文件
{
  if (filepath.isEmpty()) {//如果输入文件路径为空则返回false
      return false;
    }
  logSaver->saveLog(QStringLiteral("%1：加载脚本文件：%2").arg(objectName()).arg(filepath), LogSaver::Information);
  fileReader->readFromFile<ScriptSaveLoader>(filepath, this,&ScriptSaveLoader::slot_scriptFileData,&ScriptSaveLoader::slot_loadScriptFileFailed);
  return true;
}

void ScriptSaveLoader::slot_scriptFileData(QString filePath, QByteArray data)
{
  QJsonParseError qJsonParseError;
  QJsonDocument scriptDocument = QJsonDocument::fromJson(data, &qJsonParseError);
  if (QJsonParseError::NoError == qJsonParseError.error)//如果文件内容载入失败则返回false
    {
      if (scriptDocument.isObject())
        {
          QJsonObject scriptObject = scriptDocument.object();
          QJsonObject::iterator a;
          QVector<QVector<QVector<float>>> codeBlocks1;//准备拼装整个脚本
          for (int i = 0; i < scriptObject.size(); ++i)
            {
              QJsonObject::iterator a = scriptObject.find(QString::number(i));
              if (a->isObject())
                {
                  QJsonObject secondObject = a->toObject();
                  QVector<QVector<float>> codeBlock1;//准备拼装代码块
                  for (int j = 0; j < secondObject.size(); ++j)
                    {
                      QJsonObject::iterator b = secondObject.find(QString::number(j));
                      if (b->isObject())
                        {
                          QJsonObject thirdObject = b->toObject();
                          QVector<float> instruction1;//准备拼装指令
                          for (int k = 0; k < thirdObject.size(); ++k)
                            {
                              QJsonObject::iterator c = thirdObject.find(QString::number(k));
                              if (c->isString())
                                {
                                  instruction1.append(c->toString().toFloat());
                                }
                              else
                                {
                                  logSaver->saveLog(QStringLiteral("%1：加载脚本%2失败，json格式转换出错，坐标（%3，%4，%5）").arg(objectName()).arg(filePath).arg(i).arg(j).arg(k), LogSaver::Critical);
                                  emit signal_loadScriptFileFailed(filePath);
                                  return;
                                }
                            }
                          codeBlock1.append(instruction1);//将指令添加到当前代码块
                        }
                    }
                  codeBlocks1.append(codeBlock1);//将当前代码块添加到整个脚本
                }
            }
          bool isOk = false;
          QVector < QVector < ScriptInstruction * >> scriptList=ScriptInstructionFactory::floatListToScriptList(codeBlocks1, &isOk);
          if (isOk)
            {
              scriptRunner->setScript(scriptList);
              logSaver->saveLog(QStringLiteral("%1：加载脚本%2成功").arg(objectName()).arg(filePath), LogSaver::Information);
              emit signal_loadScriptSuccessful(filePath);
              return;
            }
        }
    }
  logSaver->saveLog(QStringLiteral("%1：加载脚本%2失败，脚本文件内容格式转换错误").arg(objectName()).arg(filePath), LogSaver::Critical);
  emit signal_loadScriptFileFailed(filePath);
  return;
}
void ScriptSaveLoader::slot_loadScriptFileFailed(QString filePath)
{
  logSaver->saveLog(QStringLiteral("%1：加载脚本%2失败，打开脚本文件失败").arg(objectName()).arg(filePath), LogSaver::Critical);
  emit signal_loadScriptFileFailed(filePath);
}
void ScriptSaveLoader::slot_saveScriptFileSuccessfule(QString filePath)
{
  logSaver->saveLog(QStringLiteral("%1：保存脚本%2成功").arg(objectName()).arg(filePath), LogSaver::Information);
  emit signal_saveScriptFileSuccessful(filePath);
}
void ScriptSaveLoader::slot_saveScriptFileFailed(QString filePath)
{
  logSaver->saveLog(QStringLiteral("%1：保存脚本%2失败，打开脚本文件失败").arg(objectName()).arg(filePath), LogSaver::Critical);
  emit  signal_saveScriptFileFailed(filePath);
}
FileWriter* ScriptSaveLoader::getFileWriter()
{
  return fileWriter;
}
void ScriptSaveLoader::setFileWriter(FileWriter* fileWriter)
{
  this->fileWriter = fileWriter;
}
FileReader* ScriptSaveLoader::getFileReader()
{
  return fileReader;
}
void ScriptSaveLoader::setFileReader(FileReader* fileReader)
{
  this->fileReader = fileReader;
}
ScriptRunner* ScriptSaveLoader::getScriptRunner()
{
  return scriptRunner;
}
void ScriptSaveLoader::setScriptRunner(ScriptRunner* scriptRunner)
{
  this->scriptRunner = scriptRunner;
}
LogSaver* ScriptSaveLoader::getLogSaver()
{
  return logSaver;
}
void ScriptSaveLoader::setLogSaver(LogSaver* logSaver)
{
  this->logSaver = logSaver;
}
int ScriptSaveLoader::getAccuracy()
{
  return accuracy;
}
void ScriptSaveLoader::setAccuracy(int accuracy)
{
  this->accuracy = accuracy;
}
